/**
 * 
 */
package com.demo2do.strawberry.entity.startup;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

import org.apache.commons.collections.CollectionUtils;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.OrderBy;

import com.alibaba.fastjson.annotation.JSONField;
import com.demo2do.core.utils.StringUtils;
import com.demo2do.strawberry.Constant;
import com.demo2do.strawberry.entity.startup.activity.Discussion;
import com.demo2do.strawberry.entity.startup.activity.Event;
import com.demo2do.strawberry.entity.startup.activity.Fans;
import com.demo2do.strawberry.entity.startup.activity.Meet;
import com.demo2do.strawberry.entity.startup.activity.Rating;
import com.demo2do.strawberry.entity.startup.detail.Profile;
import com.demo2do.strawberry.entity.startup.detail.Proposal;
import com.demo2do.strawberry.entity.startup.detail.Resource;
import com.demo2do.strawberry.entity.startup.founder.Founder;
import com.demo2do.strawberry.entity.startup.fund.Fund;
import com.demo2do.strawberry.entity.startup.fund.FundProgress;
import com.demo2do.strawberry.entity.startup.fund.FundStatus;


/**
 * @author Downpour
 */
@Entity
@Table(name = "startup")
public class Startup {
	
	@Id
	@GeneratedValue
	private Long id;
	
	/** 项目基本信息  */
	@Embedded
	private Profile profile;
	
	/** 项目标签 */
	private String tags;

	/** 项目概况  */
	@AttributeOverrides({
		@AttributeOverride(name = "detail", column = @Column(name = "proposal_detail")),
		@AttributeOverride(name = "highlight", column = @Column(name = "proposal_highlight")),
		@AttributeOverride(name = "market", column = @Column(name = "proposal_market")),
		@AttributeOverride(name = "competitor", column = @Column(name = "proposal_competitor")),
		@AttributeOverride(name = "source", column = @Column(name = "proposal_source"))
	})
	@Embedded
	@JSONField(serialize = false)
	private Proposal proposal;
	
	/** 项目视频和图片资源 */
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	@OrderBy(clause = "type ASC")
	private List<Resource> resources;
	
	/** 融资信息 */
	@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
	@Fetch(FetchMode.SELECT)
	@PrimaryKeyJoinColumn
	private Fund fund;
	
	/** 融资进度 */
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	private List<FundProgress> fundProgresses;
	
	@JSONField(serialize = false)
	private Date createTime;
	
	@Enumerated(EnumType.ORDINAL)
	@JSONField(serialize = false)
	private Status status;
	
	@Enumerated(EnumType.ORDINAL)
	@JSONField(serialize = false)
	private Type type;
	
	@Enumerated(EnumType.ORDINAL)
	private FundStatus fundStatus;
	
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@OrderBy(clause = "is_recommend DESC")
	private List<Rating> ratings;
	
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	private List<Discussion> discussions;
	
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	private List<Meet> meets;
	
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	private List<Fans> fans;
	
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	private List<Founder> founders;
	
	@OneToMany(mappedBy = "startup", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JSONField(serialize = false)
	@OrderBy(clause = "happen_date DESC")
	private List<Event> events;
	
	private int weight;
	
	@Column(name = "is_enabled")
	@JSONField(serialize = false)
	private boolean enabled;
	
	/**
	 * default constructor
	 */
	public Startup() {
		
	}
	
	/**
	 * return all video resources
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public List<Resource> getVideoResouces() {
		List<Resource> videoResources = new ArrayList<Resource>();
		if(this.resources != null) {
			for(Resource resource : this.resources) {
				if(resource.isVideo()) {
					videoResources.add(resource);
				}
			}
		}
		return videoResources;
	}

	/**
	 * @return
	 */
	public String getFansCountKey() {
		return StringUtils.connect(Constant.REDIS_STARTUPS, ":", this.id.toString(), ":", Constant.REDIS_FAN_COUNT);
	}
	
	/**
	 * @return
	 */
	public String getRatingCountKey() {
		return StringUtils.connect(Constant.REDIS_STARTUPS, ":", this.id.toString(), ":", Constant.REDIS_RATING_COUNT);
	}
	/**
	 * @return
	 */
	public String getDiscussionCountKey() {
		return StringUtils.connect(Constant.REDIS_STARTUPS, ":", this.id.toString(), ":", Constant.REDIS_DISCUSSION_COUNT);
	}

	/**
	 * @return
	 */
	public String getMeetCountKey() {
		return StringUtils.connect(Constant.REDIS_STARTUPS, ":", this.id.toString(), ":", Constant.REDIS_MEET_COUNT);
	}

	/**
	 * @return
	 */
	public String getViewCountKey() {
		return StringUtils.connect(Constant.REDIS_STARTUPS, ":", this.id.toString(), ":", Constant.REDIS_VIEW_COUNT);
	}

	/**
	 * return all picture resources
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public List<Resource> getPictureResources() {
		
		List<Resource> pictureResources = new ArrayList<Resource>();
		if(this.resources != null) {
			for(Resource resource : this.resources) {
				if(resource.isPicure()) {
					pictureResources.add(resource);
				}
			}
		}
		return pictureResources;
	}
	
	/**
	 * return the special recommend
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public Rating getRecommend() {
		if(CollectionUtils.isNotEmpty(this.ratings)) {
			return this.ratings.get(0);
		}
		return null;
	}
	
	/**
	 * return average rating
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public float getAverageRating() {
		if(CollectionUtils.isNotEmpty(this.ratings)) {
			float total = 0f;
			for(Rating rating : ratings) {
				total += (float)rating.getStar();
			}
			return total / (float)ratings.size();
		}
		return 0f;
	}
	
	/**
	 * @return
	 */
	@JSONField(serialize = false)
	public int getRatingCount() {
		if(CollectionUtils.isNotEmpty(ratings)) {
			return ratings.size();
		}
		return 0;
	}
	
	/**
	 * @return
	 */
	@JSONField(serialize = false)
	public int getDiscussionCount() {
		if(CollectionUtils.isNotEmpty(discussions)) {
			return discussions.size();
		}
		return 0;
	}
	
	/**
	 * @return
	 */
	@JSONField(serialize = false)
	public int getMeetCount() {
		if(CollectionUtils.isNotEmpty(meets)) {
			return meets.size();
		}
		return 0;
	}
	
	/**
	 * @return
	 */
	@JSONField(serialize = false)
	public int getFansCount() {
		if(CollectionUtils.isNotEmpty(fans)) {
			return fans.size();
		}
		return 0;
	}
	
	/**
	 * determine whether the startup is in funding status
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public boolean isFunding() {
		return this.fundStatus.getAlias().equals(FundStatus.FUNDING.getAlias());
	}
	
	/**
	 * determine whether the startup is in prefunding status
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public boolean isPrefunding() {
		return this.fundStatus.getAlias().equals(FundStatus.PREFUNDING.getAlias());
	}
	
	/**
	 * determine whether the startup is in latest status
	 * 
	 * @return
	 */
	@JSONField(serialize = false)
	public boolean isLatest() {
		return this.fundStatus.getAlias().equals(FundStatus.LATEST.getAlias());
	}
	
	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}

	/**
	 * @return the profile
	 */
	public Profile getProfile() {
		return profile;
	}
	
	/**
	 * @return the tags
	 */
	public String getTags() {
		return tags;
	}

	/**
	 * @return the proposal
	 */
	public Proposal getProposal() {
		return proposal;
	}

	/**
	 * @return the resources
	 */
	public List<Resource> getResources() {
		return resources;
	}

	/**
	 * @return the fund
	 */
	public Fund getFund() {
		return fund;
	}
	
	/**
	 * @return the fundProgresses
	 */
	public List<FundProgress> getFundProgresses() {
		return fundProgresses;
	}

	/**
	 * @return the createTime
	 */
	public Date getCreateTime() {
		return createTime;
	}

	/**
	 * @return the status
	 */
	public Status getStatus() {
		return status;
	}

	/**
	 * @return the type
	 */
	public Type getType() {
		return type;
	}
	
	/**
	 * @return the fundStatus
	 */
	public FundStatus getFundStatus() {
		return fundStatus;
	}
	
	/**
	 * @return the ratings
	 */
	public List<Rating> getRatings() {
		return ratings;
	}
	
	/**
	 * @return the discussions
	 */
	public List<Discussion> getDiscussions() {
		return discussions;
	}
	
	/**
	 * @return the meets
	 */
	public List<Meet> getMeets() {
		return meets;
	}
	
	/**
	 * @return the fans
	 */
	public List<Fans> getFans() {
		return fans;
	}
	
	/**
	 * @return the founders
	 */
	public List<Founder> getFounders() {
		return founders;
	}
	
	/**
	 * @return the events
	 */
	public List<Event> getEvents() {
		return events;
	}
	
	/**
	 * @return the weight
	 */
	public int getWeight() {
		return weight;
	}

	/**
	 * @return the enabled
	 */
	public boolean isEnabled() {
		return enabled;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * @param profile the profile to set
	 */
	public void setProfile(Profile profile) {
		this.profile = profile;
	}
	
	/**
	 * @param tags the tags to set
	 */
	public void setTags(String tags) {
		this.tags = tags;
	}

	/**
	 * @param proposal the proposal to set
	 */
	public void setProposal(Proposal proposal) {
		this.proposal = proposal;
	}

	/**
	 * @param resources the resources to set
	 */
	public void setResources(List<Resource> resources) {
		this.resources = resources;
	}

	/**
	 * @param fund the fund to set
	 */
	public void setFund(Fund fund) {
		this.fund = fund;
	}
	
	/**
	 * @param fundProgresses the fundProgresses to set
	 */
	public void setFundProgresses(List<FundProgress> fundProgresses) {
		this.fundProgresses = fundProgresses;
	}

	/**
	 * @param createTime the createTime to set
	 */
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	/**
	 * @param status the status to set
	 */
	public void setStatus(Status status) {
		this.status = status;
	}

	/**
	 * @param type the type to set
	 */
	public void setType(Type type) {
		this.type = type;
	}
	
	/**
	 * @param fundStatus the fundStatus to set
	 */
	public void setFundStatus(FundStatus fundStatus) {
		this.fundStatus = fundStatus;
	}
	
	/**
	 * @param ratings the ratings to set
	 */
	public void setRatings(List<Rating> ratings) {
		this.ratings = ratings;
	}
	
	/**
	 * @param discussions the discussions to set
	 */
	public void setDiscussions(List<Discussion> discussions) {
		this.discussions = discussions;
	}
	
	/**
	 * @param meets the meets to set
	 */
	public void setMeets(List<Meet> meets) {
		this.meets = meets;
	}
	
	/**
	 * @param fans the fans to set
	 */
	public void setFans(List<Fans> fans) {
		this.fans = fans;
	}
	
	/**
	 * @param founders the founders to set
	 */
	public void setFounders(List<Founder> founders) {
		this.founders = founders;
	}
	
	/**
	 * @param events the events to set
	 */
	public void setEvents(List<Event> events) {
		this.events = events;
	}

	/**
	 * @param weight the weight to set
	 */
	public void setWeight(int weight) {
		this.weight = weight;
	}
	
	/**
	 * @param enabled the enabled to set
	 */
	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

}
